package com.apes.fn.scm.vipSettle.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.fico.expense.ExpenseItem;
import com.apes.fn.scm.contract.FnContract;
import com.apes.fn.scm.contract.FnContractRepository;
import com.apes.fn.scm.retailOrder.model.*;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDiscountItemRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDiscountRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.scm.saleReport.model.TurnoverDetails;
import com.apes.fn.scm.saleReport.repository.TurnoverDetailsRepository;
import com.apes.fn.scm.saleReport.service.SaleReportSubscriberService;
import com.apes.fn.scm.vipSettle.model.VipUnionSettle;
import com.apes.fn.scm.vipSettle.model.VipUnionSettleItem;
import com.apes.fn.scm.vipSettle.repository.VipUnionSettleRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.masterdata.area.model.BusinessCircle;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.apes.fn.scm.vipSettle.model.VipUnionSettleItem.CONST_TABLE_NAME;


/**
 * @Title: vipUnionSettleService
 * @Description: 会员联盟余额结算汇总
 * @author: cyy
 * @create: 2022/7/4 14:18
 */
@Service("vipUnionSettleService")
public class VipUnionSettleService extends DomainService {
    @Autowired
    private VipUnionSettleFormula vipUnionSettleFormula;
    @Autowired
    private RetailOrderRepository retailOrderRepository;
    @Autowired
    private StoreRepository storeRepository;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private VipUnionSettleRepository vipUnionSettleRepository;
    @Autowired
    private RetailOrderDiscountRepository retailOrderDiscountRepository;
    @Autowired
    private RetailOrderDiscountItemRepository retailOrderDiscountItemRepository;
    @Autowired
    private DeptRepository deptRepository;
    @Autowired
    private EnumerationRepository enumerationRepository;
    @Autowired
    private SequenceService sequenceService;
    @Autowired
    private AccessProviderRepository accessProviderRepository;
    @Autowired
    private TurnoverDetailsRepository turnoverDetailsRepository;

    @OutboxSubscriber(id = "vip_union_retail_order", name = "零售单写入会员联盟", condition = "state == 'done' || state == 'vouched'")
    public void execVipSettle(RetailOrder order) {
        RetailOrder retailOrder = retailOrderRepository.findRetailOrder(order.getId());
        if (retailOrder == null) throw new RuntimeException("请确定零售单已生成");
        // 控制重复生成
        int count = vipUnionSettleRepository.findByRetailOrder(retailOrder.getId());
        if(count != 0) return;
        // 会员联盟储值表
        createPaymentMethodVipSettle(retailOrder);
        // 会员联盟折扣表
        createDiscountMethodVipSettle(retailOrder);
        List<VipUnionSettle> vipUnionSettles = vipUnionSettleRepository.findByType(retailOrder.getId());
        if(vipUnionSettles.size() != 0){
            vipUnionSettles.forEach(vipUnionSettle -> vipUnionSettle.getVipUnionSettleItems().forEach(vipUnionSettleItem -> {
                //回写金额到营业额明细
                TurnoverDetails turnoverDetails = turnoverDetailsRepository.findByOriginAndOriginItem(retailOrder.getId(), vipUnionSettleItem.getRetailOrderItem());
                if(turnoverDetails == null) throw new RuntimeException("零售单："+retailOrder.getId()+"或零售明细："+vipUnionSettleItem.getRetailOrderItem()+"未生成营业额明细");
                if(vipUnionSettleItem.getVipBalanceType() == 2){
                    turnoverDetails.setVipUnionAmount(vipUnionSettleItem.getCouponFlow() + turnoverDetails.getVipUnionAmount());
                } else {
                    turnoverDetails.setVipUnionAmount(vipUnionSettleItem.getSettlementAmount() + turnoverDetails.getVipUnionAmount());
                }
                turnoverDetails.setOriginUpdateDate(new Date());
                turnoverDetailsRepository.saveAndFlush(turnoverDetails);
            }));
        }
    }

    private void execVipSettleByTime(){
        List<Map> paymentMethodList = vipUnionSettleFormula.findPaymentMethodByTime();
        for(int i=0;i<paymentMethodList.size();i++){
            String  retailOrderId = paymentMethodList.get(i).get("ID").toString();
            RetailOrder retailOrder = retailOrderRepository.findRetailOrder(retailOrderId);
            //生成主表
            createPaymentMethodVipSettle(retailOrder);
        }
        List<Map> discountList = vipUnionSettleFormula.findDiscountByTime();
        for(int i=0;i<discountList.size();i++){
            String  retailOrderId = discountList.get(i).get("ID").toString();
            RetailOrder retailOrder = retailOrderRepository.findRetailOrder(retailOrderId);
            //生成明细表
            createDiscountMethodVipSettle(retailOrder);
        }
    }

    /**
     * 创建会员联盟储值表
     * 这里只取零售单收款方式中 收款方式为 05 储值类型
     *
     * @param retailOrder 零售单
     */
    private void createPaymentMethodVipSettle(RetailOrder retailOrder) {
        String companyId = retailOrder.getCompany().getId();
        AtomicReference<Boolean> mark = new AtomicReference<>(true);
        retailOrder.getPaymentMethodSet().stream()
                .filter(payMethod -> "05".equals(payMethod.getPaymentMethodType().getId()))   // 只判断 05 储值部分
                .forEach(payMethod -> {
                    // 判断收款方式明细数据
                    payMethod.getRetailPayMethodItems()
                            .forEach(payMethodItem -> {
                                if(payMethodItem.getCompany() == null) throw new RuntimeException("付款方式明细公司为空");
                                // 同公司不计算
                                if(payMethodItem.getCompany().getId().equals(companyId)){
                                    mark.set(false);
                                    return;
                                }
                                // 创建会员联盟数据
                                createBalanceVipSettle(retailOrder, payMethodItem);
                            });
                    if(!mark.get()) return;
                });
    }

    /**
     * 保存会员联盟储值主表支出和收入
     *
     * @param retailOrder   零售单
     * @param payMethodItem 付款方式明细
     */
    private void createBalanceVipSettle(RetailOrder retailOrder, RetailPayMethodItem payMethodItem) {
        // 生成收入方会员联盟数据
        VipUnionSettle vipUnionSettleIn = getVipUnionSettleModel(retailOrder, payMethodItem);
        vipUnionSettleIn.setPaymentMethodType("balance");
        double amount = payMethodItem.getAmount();
        vipUnionSettleIn.setUseSavings(amount);
        vipUnionSettleIn.setSettlementAmount(amount);

        // 计算费用
        vipUnionSettleIn.setGiveSavings(getGiveSavings(vipUnionSettleIn, payMethodItem.getVipAlliance().getId()));
        // 取平台服务费率策略
        Map strategyMap = strategyMap(retailOrder.getCompany().getId());
        vipUnionSettleIn.setPlatformManagementFee(getPlatformFee(vipUnionSettleIn, strategyMap));
        vipUnionSettleIn = vipUnionSettleRepository.saveAndFlush(vipUnionSettleIn);

        // 生成支出方会员联盟数据
        saveVipUnionSettleOut(vipUnionSettleIn);

    }

    /**
     * 获取会员联盟储值表模型数据
     *
     * @param retailOrder   RetailOrder
     * @param payMethodItem RetailPayMethodItem
     * @return VipUnionSettle
     */
    private VipUnionSettle getVipUnionSettleModel(RetailOrder retailOrder, RetailPayMethodItem payMethodItem) {
        // 主表数据
        VipUnionSettle vipUnionSettle = new VipUnionSettle();
        vipUnionSettle.setType("in");
        vipUnionSettle.setState("done");
        FnCustomerExpand customerExpand = retailOrder.getCustomerExpand();
        vipUnionSettle.setFnCustomerExpand(customerExpand);
        vipUnionSettle.setCarLicense(customerExpand.getCarLicense());

        vipUnionSettle.setRetailOrder(retailOrder.getId());
        vipUnionSettle.setDept(retailOrder.getDept());
        vipUnionSettle.setCompany(retailOrder.getCompany());
        vipUnionSettle.setPartnerDept(payMethodItem.getDept());
        vipUnionSettle.setPartnerCompany(payMethodItem.getCompany());
        vipUnionSettle.setVipAlliance(payMethodItem.getVipAlliance());

        vipUnionSettle.setReceiptDate(retailOrder.getDateDone());
        vipUnionSettle.setStatisticDate(new Date());

        vipUnionSettle.setOriginBusinessType(retailOrder.getOrderType());
        vipUnionSettle.setOrigin(retailOrder.getOrigin());
        vipUnionSettle.setSourceBusinessType(retailOrder.getSourceBusinessType());
        vipUnionSettle.setSource(retailOrder.getSource());

        // 商圈
        BusinessCircle businessCircle = storeRepository.findByDept(retailOrder.getDept()).getBusinessCircle();
        vipUnionSettle.setBusinessCircle(businessCircle);

        // 接入商
        AccessProvider accessProvider = accessProviderRepository.findByCompany(retailOrder.getCompany().getId());
        AccessProvider otherAccessProvider = accessProviderRepository.findByCompany(payMethodItem.getCompany().getId());
        vipUnionSettle.setAccessProvider(accessProvider);
        vipUnionSettle.setOtherAccessProvider(otherAccessProvider);
        vipUnionSettle.setPlatformCompany(partyRoleRepository.findOne("1007"));
        return vipUnionSettle;
    }

    /**
     * 拷贝并保存会员联盟储值表支出部分
     *
     * @param vipUnionSettle 储值表
     */
    private void saveVipUnionSettleOut(VipUnionSettle vipUnionSettle) {
        VipUnionSettle vipUnionSettleOut = new VipUnionSettle();
        ReflectUtil.copyAll(vipUnionSettle, vipUnionSettleOut, "id", "platformManagementFee");
        PartyRole company = vipUnionSettle.getPartnerCompany();
        vipUnionSettleOut.setCompany(company);
        vipUnionSettleOut.setDept(vipUnionSettle.getPartnerDept());
        vipUnionSettleOut.setPartnerCompany(vipUnionSettle.getCompany());
        vipUnionSettleOut.setPartnerDept(vipUnionSettle.getDept());
        vipUnionSettleOut.setType("out");
        vipUnionSettleOut.setGiveSavings(vipUnionSettle.getGiveSavings() * -1);
        vipUnionSettleOut.setSettlementAmount(vipUnionSettle.getSettlementAmount() * -1);
        vipUnionSettleOut.setAccessProvider(vipUnionSettle.getOtherAccessProvider());
        vipUnionSettleOut.setOtherAccessProvider(vipUnionSettle.getAccessProvider());
        vipUnionSettle.setPlatformCompany(partyRoleRepository.findOne("1007"));
        // 取平台服务费率策略
        Map strategyMap = strategyMap(vipUnionSettle.getPartnerCompany().getId());
        vipUnionSettleOut.setPlatformManagementFee(-1 * getPlatformFee(vipUnionSettle, strategyMap));
        vipUnionSettleOut.setVipUnionSettleItems(new HashSet<>());
        vipUnionSettleRepository.saveAndFlush(vipUnionSettleOut);
    }

    /**
     * 生成会员联盟余额表并生成折扣关联表
     *
     * @param retailOrder 零售单
     */
    private void createDiscountMethodVipSettle(RetailOrder retailOrder) {
        List<RetailOrderDiscount> retailOrderDiscounts = retailOrderDiscountRepository.findAllByRetailOrderId(retailOrder.getId());
        retailOrderDiscounts.forEach(retailOrderDiscount -> {
            if (retailOrderDiscount == null) return;
            //是否是同公司余额
            List<Map> details = retailOrderDiscountItemRepository.findByDiscountId(retailOrderDiscount.getId());
            //如果只有一个公司
            if (details.size() == 1) {
                createByOnlyCompany(details, retailOrder, retailOrderDiscount, retailOrderDiscount.getRetailOrderItem());
            } else {
                details.forEach(detail -> createByManyCompany(detail, retailOrderDiscount, retailOrderDiscount.getRetailOrderItem(), retailOrder));
            }
        });
    }


    /**
     * 明细表只有一个公司,生成一张主表多张明细表
     * @param details 公司,部门,会员联盟idMap
     * @param retailOrder
     * @param discount
     * @param retailOrderItem
     */
    private void createByOnlyCompany(List<Map> details, RetailOrder retailOrder,
                                     RetailOrderDiscount discount,
                                     RetailOrderItem retailOrderItem) {
        List<VipUnionSettleItem> vipUnionSettleItemsIn = new ArrayList<>();
        List<VipUnionSettleItem> vipUnionSettleItemsOut = new ArrayList<>();
        Map idMap = details.get(0);
        PartyRole discountCompany = partyRoleRepository.findById(idMap.get("companyId").toString()).get();
        AtomicInteger vipBalanceType = new AtomicInteger();
        discount.getRetailDiscountItems().forEach(discountItem -> {
            vipBalanceType.set(vipBalanceType(discountItem, discount.getDiscountType().getId()));
//            listType.add(vipBalanceType(discountItem, discountType))
            //折扣公司与零售单公司不能相同
            if (!discountItem.getCompany().getId().equals(retailOrder.getCompany().getId())){
                //生成明细表正单
                VipUnionSettleItem vipUnionSettleItemIn = createVipUnionSettleItem(retailOrder,retailOrderItem,discount,discountItem);
                vipUnionSettleItemsIn.add(vipUnionSettleItemIn);
                //生成明细表负单
                VipUnionSettleItem vipUnionSettleItemOut = copyVipUnionSettleItem(vipUnionSettleItemIn);
                vipUnionSettleItemsOut.add(vipUnionSettleItemOut);
            }
        });
        if (vipUnionSettleItemsIn.size() == 0) return;
        Dept discountDept = deptRepository.findById(idMap.get("deptId").toString()).get();
        Enumeration vipAlliance = enumerationRepository.findById(idMap.get("vipAllianceId").toString()).get();
        VipUnionSettle vipUnionIn = vipUnionSettleRepository.existsVipSettleDiscount(retailOrder.getId(), retailOrder.getCompany().getId(),
                retailOrder.getDept().getId(),discountDept.getId(), discountCompany.getId(), vipBalanceType.get(), "in");
        VipUnionSettle vipUnionOut = vipUnionSettleRepository.existsVipSettleDiscount(retailOrder.getId(), discountCompany.getId(),discountDept.getId(),
                retailOrder.getDept().getId(), retailOrder.getCompany().getId(), vipBalanceType.get(), "out");
        if (vipUnionIn != null && vipUnionOut != null) {
            addVipUnion(vipUnionSettleItemsIn,vipUnionSettleItemsOut,vipUnionIn,vipUnionOut);
        } else {
            saveVipUnion(retailOrder,discountCompany,discountDept,vipAlliance,vipUnionSettleItemsIn,vipUnionSettleItemsOut);
        }
    }

    /**
     * 明细表有多家公司,有几家公司生成几张主表和明细表
     * @param detail 公司,部门,会员联盟idMap
     * @param discount
     * @param retailOrderItem
     * @param retailOrder
     */
    private void createByManyCompany(Map detail, RetailOrderDiscount discount, RetailOrderItem retailOrderItem, RetailOrder retailOrder) {
        String companyId = detail.get("companyId").toString();
        String deptId = detail.get("deptId").toString();
        String vipAllianceId = detail.get("vipAllianceId").toString();
        String type = detail.get("type").toString();
        List<RetailOrderDiscountItem> discountItems = retailOrderDiscountItemRepository.findByDiscountIdCompanyIdDeptIdVipAllianceId(discount.getId(), companyId, deptId, vipAllianceId,type);
        discountItems.forEach(discountItem ->{
            //折扣公司与零售单公司不能相同
            if (!discountItem.getCompany().getId().equals(retailOrder.getCompany().getId())) {
                int vipBalanceType = vipBalanceType(discountItem, discount.getDiscountType().getId());
                //生成明细表正单
                VipUnionSettleItem vipUnionSettleItemIn = createVipUnionSettleItem(retailOrder,retailOrderItem,discount,discountItem);
                //生成明细表负单
                VipUnionSettleItem vipUnionSettleItemOut = copyVipUnionSettleItem(vipUnionSettleItemIn);
                VipUnionSettle vipUnionIn = vipUnionSettleRepository.existsVipSettleDiscount(retailOrder.getId(), retailOrder.getCompany().getId(),
                        retailOrder.getDept().getId(),deptId, companyId, vipBalanceType, "in");
                VipUnionSettle vipUnionOut = vipUnionSettleRepository.existsVipSettleDiscount(retailOrder.getId(), companyId,deptId,
                        retailOrder.getDept().getId(), retailOrder.getCompany().getId(), vipBalanceType, "out");
                if (vipUnionIn != null && vipUnionOut != null) {
                    addVipUnion(Collections.singletonList(vipUnionSettleItemIn), Collections.singletonList(vipUnionSettleItemOut),
                            vipUnionIn,vipUnionOut);
                } else {
                    //保存主表和明细表
                    saveVipUnion(retailOrder,discountItem.getCompany(),discountItem.getDept(),
                            vipUnionSettleItemIn.getVipAlliance(),
                            Collections.singletonList(vipUnionSettleItemIn), Collections.singletonList(vipUnionSettleItemOut));
                }
            }
        });

    }



    /**
     * 一条折扣主表，多条相同余额类型折扣明细数据
     * @param vipUnionSettleItemsIn
     * @param vipUnionSettleItemsOut
     * @param vipUnionIn
     * @param vipUnionOut
     */
    private void addVipUnion(List<VipUnionSettleItem> vipUnionSettleItemsIn, List<VipUnionSettleItem> vipUnionSettleItemsOut,
                             VipUnionSettle vipUnionIn, VipUnionSettle vipUnionOut) {
        //拿到当前明细表的结算金额
        double settlementAmount = vipUnionSettleItemsIn.stream().mapToDouble(VipUnionSettleItem::getSettlementAmount).sum() + vipUnionIn.getSettlementAmount();
        vipUnionIn.setSettlementAmount(Arith.round(settlementAmount,2));
        vipUnionOut.setSettlementAmount(Arith.round(-settlementAmount,2));
        // 取平台服务费率策略

        Map strategyMap = strategyMap(retailOrderRepository.findRetailOrder(vipUnionIn.getRetailOrder()).getCompany().getId());
        vipUnionIn.setPlatformManagementFee(getPlatformFee(vipUnionIn, strategyMap));
        vipUnionOut.setPlatformManagementFee(0);
        vipUnionSettleItemsIn.forEach(itemIn -> itemIn.setVipUnionSettle(vipUnionIn));
        vipUnionSettleItemsOut.forEach(itemOut -> itemOut.setVipUnionSettle(vipUnionOut));
        vipUnionIn.getVipUnionSettleItems().addAll(vipUnionSettleItemsIn);
        vipUnionOut.getVipUnionSettleItems().addAll(vipUnionSettleItemsOut);

    }

    /**
     * 保存会员联盟折扣主表支出和收入
     *
     * @param retailOrder   零售单
     * @param discountCompany 折扣明细公司
     * @param discountDept 折扣明细部门
     * @param vipAlliance 会员联盟
     *
     */
    private void saveVipUnion(RetailOrder retailOrder,PartyRole discountCompany,Dept discountDept,Enumeration vipAlliance,
                              List<VipUnionSettleItem> vipUnionSettleItemsIn,List<VipUnionSettleItem> vipUnionSettleItemsOut) {
        // 生成收入方会员联盟数据
        VipUnionSettle vipUnionSettleIn = getVipUnionModelByDiscount(retailOrder, discountCompany,discountDept,vipAlliance);
        vipUnionSettleIn.setPaymentMethodType("discount");
        vipUnionSettleIn.setUseSavings(0);
        double settlementAmount = vipUnionSettleItemsIn.stream().mapToDouble(VipUnionSettleItem::getSettlementAmount).sum();
        vipUnionSettleIn.setSettlementAmount(Arith.round(settlementAmount,2));

        // 计算费用
        vipUnionSettleIn.setGiveSavings(getGiveSavings(vipUnionSettleIn, vipAlliance.getId()));
        // 取平台服务费率策略

        Map strategyMap = strategyMap(retailOrderRepository.findRetailOrder(vipUnionSettleIn.getRetailOrder()).getCompany().getId());
        vipUnionSettleIn.setPlatformManagementFee(getPlatformFee(vipUnionSettleIn, strategyMap));
        vipUnionSettleIn.setVipUnionSettleItems(new HashSet<>(vipUnionSettleItemsIn));
        vipUnionSettleIn = vipUnionSettleRepository.saveAndFlush(vipUnionSettleIn);

        // 生成支出方会员联盟数据
        saveVipUnionSettleOutByDiscount(vipUnionSettleIn,vipUnionSettleItemsOut);
    }

    /**
     * 获取会员联盟折扣主表模型数据
     *
     * @param retailOrder   零售单
     * @param discountCompany 折扣明细公司
     * @param discountDept 折扣明细公部门
     * @return VipUnionSettle
     */
    private VipUnionSettle getVipUnionModelByDiscount(RetailOrder retailOrder,PartyRole discountCompany,Dept discountDept,Enumeration vipAlliance) {
        // 主表数据
        VipUnionSettle vipUnionSettle = new VipUnionSettle();
        vipUnionSettle.setType("in");
        vipUnionSettle.setState("done");
        FnCustomerExpand customerExpand = retailOrder.getCustomerExpand();
        vipUnionSettle.setFnCustomerExpand(customerExpand);
        vipUnionSettle.setCarLicense(customerExpand.getCarLicense());

        vipUnionSettle.setRetailOrder(retailOrder.getId());
        vipUnionSettle.setDept(retailOrder.getDept());
        vipUnionSettle.setCompany(retailOrder.getCompany());
        vipUnionSettle.setPartnerDept(discountDept);
        vipUnionSettle.setPartnerCompany(discountCompany);
        vipUnionSettle.setVipAlliance(vipAlliance);

        vipUnionSettle.setReceiptDate(retailOrder.getDateDone());
        vipUnionSettle.setStatisticDate(new Date());

        vipUnionSettle.setOriginBusinessType(retailOrder.getOrderType());
        vipUnionSettle.setOrigin(retailOrder.getOrigin());
        vipUnionSettle.setSourceBusinessType(retailOrder.getSourceBusinessType());
        vipUnionSettle.setSource(retailOrder.getSource());

        // 商圈
        BusinessCircle businessCircle = storeRepository.findByDept(retailOrder.getDept()).getBusinessCircle();
        vipUnionSettle.setBusinessCircle(businessCircle);

        // 接入商
        AccessProvider accessProvider = accessProviderRepository.findByCompany(retailOrder.getCompany().getId());
        AccessProvider otherAccessProvider = accessProviderRepository.findByCompany(discountCompany.getId());
        vipUnionSettle.setAccessProvider(accessProvider);
        vipUnionSettle.setOtherAccessProvider(otherAccessProvider);
        vipUnionSettle.setPlatformCompany(partyRoleRepository.findOne("1007"));
        return vipUnionSettle;
    }

    /**
     * 拷贝并保存会员联盟折扣主表支出部分
     *
     * @param vipUnionSettle 折扣表
     */
    private void saveVipUnionSettleOutByDiscount(VipUnionSettle vipUnionSettle,List<VipUnionSettleItem> vipUnionSettleItemsOut) {
        VipUnionSettle vipUnionSettleOut = new VipUnionSettle();
        ReflectUtil.copyAll(vipUnionSettle, vipUnionSettleOut, "id", "platformManagementFee");
        PartyRole company = vipUnionSettle.getPartnerCompany();
        vipUnionSettleOut.setCompany(company);
        vipUnionSettleOut.setDept(vipUnionSettle.getPartnerDept());
        vipUnionSettleOut.setPartnerCompany(vipUnionSettle.getCompany());
        vipUnionSettleOut.setPartnerDept(vipUnionSettle.getDept());
        vipUnionSettleOut.setAccessProvider(vipUnionSettle.getOtherAccessProvider());
        vipUnionSettleOut.setOtherAccessProvider(vipUnionSettle.getAccessProvider());
        vipUnionSettleOut.setType("out");

        vipUnionSettle.setPlatformCompany(partyRoleRepository.findOne("1007"));
        vipUnionSettleOut.setGiveSavings(vipUnionSettle.getGiveSavings() * -1);
        vipUnionSettleOut.setSettlementAmount(vipUnionSettle.getSettlementAmount() * -1);
        vipUnionSettleOut.setVipUnionSettleItems(new HashSet<>(vipUnionSettleItemsOut));
        vipUnionSettleRepository.saveAndFlush(vipUnionSettleOut);
    }

    /**
     * 计算会员联盟折扣明细各金额
     * @param retailOrder
     * @param retailOrderItem
     * @param discount
     * @param discountItem
     * @return
     */
    private VipUnionSettleItem createVipUnionSettleItem(RetailOrder retailOrder, RetailOrderItem retailOrderItem,
                                                        RetailOrderDiscount discount, RetailOrderDiscountItem discountItem) {
        VipUnionSettleItem vipUnionSettleItem = createVipUnionItem(retailOrder, retailOrderItem, discount, discountItem);
        //使用金额
        double amountUsed;
        if (vipUnionSettleItem.getVipBalanceType() == 2) {
            amountUsed = discount.getCouponProfitAmount();
        } else {
            amountUsed = discountItem.getAmount();
        }
        vipUnionSettleItem.setAmountUsed(amountUsed);

        //应结金额
        double settlementAmount = getDiscountSettlementAmount(vipUnionSettleItem,discount,discountItem,retailOrder,retailOrderItem,amountUsed);
        vipUnionSettleItem.setSettlementAmount(settlementAmount);

        //税率
        double tax = retailOrderItem.getTax().getAmt() * 0.01;
        double giveTax = settlementAmount / (1 + tax) * tax;
        vipUnionSettleItem.setGiveTax(Arith.round(giveTax,2));

        //卡券引流费
        if (vipUnionSettleItem.getVipBalanceType() == 2) {
            vipUnionSettleItem.setCouponFlow(Arith.round((amountUsed - settlementAmount) * -1,2));
        }


        AccessProvider accessProvider = accessProviderRepository.findByCompany(retailOrder.getCompany().getId());
        AccessProvider otherAccessProvider = accessProviderRepository.findByCompany(discountItem.getCompany().getId());

        // 取平台服务费率策略
        Map strategyMap = strategyMap(retailOrder.getCompany().getId());
        double platformManagementFee;       //平台服务费
        if (accessProvider.getId().equals(otherAccessProvider.getId())){
            platformManagementFee = 0;
        } else if("1".equals(strategyMap.get("noFind"))){
            platformManagementFee = 0;
        } else {
            platformManagementFee = settlementAmount * Double.parseDouble(strategyMap.get("T001").toString());
        }
        vipUnionSettleItem.setPlatformManagementFee(Arith.round(platformManagementFee,2));
        return vipUnionSettleItem;
    }

    /**
     * 新增会员联盟折扣明细数据
     * @param retailOrder
     * @param retailOrderItem
     * @param discount
     * @param discountItem
     * @return
     */
    private VipUnionSettleItem createVipUnionItem(RetailOrder retailOrder,RetailOrderItem retailOrderItem,RetailOrderDiscount discount,RetailOrderDiscountItem discountItem){
        VipUnionSettleItem vipUnionSettleItem = new VipUnionSettleItem();
        vipUnionSettleItem.setId(sequenceService.getId(CONST_TABLE_NAME));

        //金额
        vipUnionSettleItem.setPrimaryPriceUnit(retailOrderItem.getOriginalSalesUnitPrice());
        vipUnionSettleItem.setSalePrice(retailOrderItem.getPriceUnit());
        double referTax = retailOrderItem.getReferTax();
        vipUnionSettleItem.setCostPrice(referTax);
        Product product = retailOrderItem.getProduct();
        vipUnionSettleItem.setProduct(product);
        vipUnionSettleItem.setTax(retailOrderItem.getTax());
        vipUnionSettleItem.setUom(retailOrderItem.getUom());

        //零售单
        vipUnionSettleItem.setRetailOrder(retailOrder.getId());
        vipUnionSettleItem.setRetailOrderItem(retailOrderItem.getId());
        vipUnionSettleItem.setServeType(retailOrderItem.getProduct().getServeType());
        Enumeration vipAlliance = discountItem.getVipAlliance();
        vipUnionSettleItem.setVipAlliance(vipAlliance);
        int vipBalanceType = vipBalanceType(discountItem, discount.getDiscountType().getId());
        vipUnionSettleItem.setVipBalanceType(vipBalanceType);
        int couponDiscountType = discount.getCouponDiscountType();
        vipUnionSettleItem.setCouponDiscountType(couponDiscountType);
        return vipUnionSettleItem;
    }

    /**
     * 计算折扣应结
     *
     * @param vipUnionSettleItem VipUnionSettleItem
     * @return 折扣应结
     */
    private double getDiscountSettlementAmount(VipUnionSettleItem vipUnionSettleItem,
                                               RetailOrderDiscount discount,RetailOrderDiscountItem discountItem,
                                               RetailOrder retailOrder,RetailOrderItem retailOrderItem,double amountUsed) {
        String businessCircleId = storeRepository.findByDept(retailOrder.getDept()).getBusinessCircle().getId();
        String classifyId = retailOrderItem.getProduct().getClassify().getId();
        int DKLX = 0;
        if(vipUnionSettleItem.getCouponDiscountType() == 1){
            DKLX = 0;
        } else if(vipUnionSettleItem.getCouponDiscountType() == 2){
            DKLX = 1;
        }

        Map map = MapUtil.mapper("VIP_ALLIANCE", vipUnionSettleItem.getVipAlliance().getId(),
                "BUSINESS_CIRCLE_ID",businessCircleId,"CLASSIFY_ID",classifyId,
                "DKLX",DKLX ,"PRODUCT_ID", vipUnionSettleItem.getProduct().getId(),
                "DISCOUNT_TYPE", discount.getDiscountType().getId(),"ITEM_TYPE", discountItem.getType(),
                "ORDER_TYPE", retailOrder.getOrderType(),"CLASSIFY_ID_FIRST", classifyId.substring(0, 1),
                "PRICE_OUT_UNIT_IN_TAX", retailOrderItem.getPriceOutUnitInTax(),"ORIGINAL_SALES_UNIT_PRICE", retailOrderItem.getOriginalSalesUnitPrice(),
                "REFER_TAX", retailOrderItem.getReferTax(),"AMOUNT_USED", amountUsed);
        //取会员联盟策略
        JSONObject result = getConditionStrategy(map, "VIP_SETTLE");
        map.putAll(result);
        if ("1".equals(result.getString("sys_break")) && !"1".equals(map.get("OUT_SYSTEM_BUSINESS").toString()))
            return 0;
        //应结金额
        double settlementAmount = getVipSettleItemSettlementAmount(map);
        return settlementAmount;
    }

    /**
     * 计算储值应结
     *
     * @param vipUnionSettle VipUnionSettle
     * @param vipAllianceId  会员联盟
     * @return 储值应结
     */
    private double getGiveSavings(VipUnionSettle vipUnionSettle, String vipAllianceId) {
        Map map = MapUtil.mapper("VIP_ALLIANCE", vipAllianceId, "BUSINESS_CIRCLE_ID", vipUnionSettle.getBusinessCircle().getId());
        JSONObject result = getConditionStrategy(map, "VIP_SETTLE");
        if (result.get("sys_break") != null && (result.get("sys_break").equals("1") && !map.get("OUT_SYSTEM_BUSINESS").toString().equals("1")))
            return vipUnionSettle.getUseSavings();
        double giveSavings = vipUnionSettle.getUseSavings() * result.getDouble("T021");
        return giveSavings;
    }

    /**
     * 生成会员联盟折扣明细支出单
     * @param vipUnionSettleItem
     * @return
     */
    private VipUnionSettleItem copyVipUnionSettleItem(VipUnionSettleItem vipUnionSettleItem) {
        VipUnionSettleItem vipUnionSettleItemOut = new VipUnionSettleItem();
        ReflectUtil.copyAll(vipUnionSettleItem, vipUnionSettleItemOut, "id", "platformManagementFee");
        vipUnionSettleItemOut.setId(sequenceService.getId(CONST_TABLE_NAME));
        vipUnionSettleItemOut.setSettlementAmount(vipUnionSettleItem.getSettlementAmount() * -1);
        vipUnionSettleItemOut.setGiveTax(vipUnionSettleItem.getGiveTax() * -1);
        if (vipUnionSettleItem.getVipBalanceType() == 2) {
            vipUnionSettleItemOut.setCouponFlow(Arith.round(vipUnionSettleItem.getCouponFlow() * -1,2));
        }
        return vipUnionSettleItemOut;
    }

    /**
     * 判断折扣余额类型
     * @param discountItem
     * @param discountType
     * @return
     */
    private int vipBalanceType(RetailOrderDiscountItem discountItem, String discountType) {
        int vipBalanceType = 0;
        String itemType = discountItem.getType();
        //商品使用余额类型
        if ("001598".equals(discountType) && "1".equals(itemType)) {
            //保呗
            vipBalanceType = 1;
        } else if ("001598".equals(discountType) && "0".equals( itemType)) {
            //红包
            vipBalanceType = 3;
        } else if ("001600".equals(discountType)) {
            //卡券
            vipBalanceType = 2;
        }
        return vipBalanceType;
    }



    /**
     * 计算平台服务费
     *
     * @param vipUnionSettle
     * @param strategyMap    平台服务费策略
     * @return
     */
    private double getPlatformFee(VipUnionSettle vipUnionSettle, Map strategyMap) {
        // 数据检查
        if (vipUnionSettle.getAccessProvider().getId().equals(vipUnionSettle.getOtherAccessProvider().getId())) return 0;
        if ("1".equals(strategyMap.get("noFind"))) return 0;
        double platformManagementFee = vipUnionSettle.getSettlementAmount() * Double.parseDouble(strategyMap.get("T001").toString());
        return Arith.round(platformManagementFee,2);
    }

    /**
     * 计算应结金额
     * @param map
     * @return
     */
    private double getVipSettleItemSettlementAmount(Map map) {
        double settlementAmount = 0;
        //保呗
        if ("001598".equals(map.get("DISCOUNT_TYPE")) && "1".equals(map.get("ITEM_TYPE"))) {
            settlementAmount = calculate(map.get("AMOUNT_USED")) * calculate(map.get("T024"));
            //红包
        } else if ("001598".equals(map.get("DISCOUNT_TYPE")) && "0".equals(map.get("ITEM_TYPE"))) {
            settlementAmount = calculate(map.get("AMOUNT_USED")) * calculate(map.get("T022"));
            //卡券
        } else if ("001600".equals(map.get("DISCOUNT_TYPE"))) {
            if (!"0.0".equals(map.get("T001").toString())) {
                settlementAmount = calculate(map.get("T001"));
            } else if (!"0.0".equals(map.get("T002").toString())) {
                settlementAmount = calculate(map.get("T002"));
            } else if (!"0.0".equals(map.get("T003").toString())) {
                //分类id为m开头
                if ("M".equals(map.get("CLASSIFY_ID_FIRST"))) {
                    //考核成本价不为0
                    if (!"0.0".equals(map.get("REFER_TAX"))) {
                        settlementAmount = calculate(map.get("REFER_TAX")) * calculate(map.get("T003"));
                    } else {
                        //为0就拿含税待安成本价
                        settlementAmount = calculate(map.get("PRICE_OUT_UNIT_IN_TAX")) * calculate(map.get("T003"));
                    }
                    //分类id为s开头
                } else if ("S".equals(map.get("CLASSIFY_ID_FIRST"))) {
                    //原销售单价
                    settlementAmount = calculate(map.get("ORIGINAL_SALES_UNIT_PRICE")) * calculate(map.get("T003"));
                }
            } else if ("M".equals(map.get("CLASSIFY_ID_FIRST"))) {
                if (map.get("REFER_TAX") != "0") {
                    settlementAmount = calculate(map.get("REFER_TAX")) * calculate(map.get("T012"));
                } else {
                    settlementAmount = calculate(map.get("PRICE_OUT_UNIT_IN_TAX")) * calculate(map.get("T012"));
                }
            } else if ("S".equals(map.get("CLASSIFY_ID_FIRST"))) {
                settlementAmount = calculate(map.get("ORIGINAL_SALES_UNIT_PRICE")) * calculate(map.get("T023"));
            }
            if ("retailReturn".equals(map.get("ORDER_TYPE"))) {
                settlementAmount = -1 * settlementAmount;
            }
        }
        return Arith.round(settlementAmount,2);

    }

    private double calculate(Object obj) {
        return Double.parseDouble(String.valueOf(obj));
    }

    /**
     * 平台服务费率策略
     * @param
     * @return
     */
    private Map<String, Object> strategyMap(String companyId) {
        String OPERATION = vipUnionSettleRepository.findOperation(companyId).getId();
        Map<String, Object> strategyMap = new HashMap<>();
        strategyMap.put("COMPANY_ID", companyId);
        strategyMap.put("OPERATION", OPERATION);
        strategyMap.put("SYS_RQ", new Date());
        strategyMap.put("conditionId", "FW01");
        //取平台服务费
        Object invoke = this.invoke("condition.getCondition", strategyMap);
        JSONObject FW01 = JSONObject.parseObject(invoke.toString());
        //是否取到
        if (FW01.get("sys_break") != null && FW01.get("sys_break").equals("1")) {
            strategyMap.put("noFind", "1");
        } else {
            strategyMap.putAll(FW01);
        }
        return strategyMap;
    }

    /**
     * 查询条件策略
     * @param map
     * @param conditionId
     * @return
     */
    private JSONObject getConditionStrategy(Map<String, Object> map, String conditionId) {
        map.put("SYS_RQ", new Date());
        map.put("conditionStrategyId", conditionId);
        Object obj = this.invoke("condition.execConditionStrategy", map);
        Map resultMap = MapUtil.mapped(obj);
        JSONObject result = new JSONObject(resultMap);
        return result;
    }

    private Map<String,Object> getDiscountSettlementAmountToApp(SimpleRequest request) {
        JSONObject jo = request.getJO();
        String vipBalanceType = jo.getString("vipBalanceType");
        String classifyId = jo.getString("classifyId");
        String productId = jo.getString("productId");
        String discountType = "";
        String type = "";
        switch (vipBalanceType){
            //保呗
            case "BB":
                discountType = "001598";
                type = "1";
                break;
            //卡券
            case "KQ":
                discountType = "001600";
                break;
            //红包
            case "HB":
                discountType = "001598";
                type = "0";
                break;
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("conditionStrategyId", "CG01");
        jsonObject.put("SYS_RQ", new Date());
        jsonObject.put("SYS_NO_CHECK", "SUPPLIER_ID,COMPANY_ID,CITY");
        jsonObject.put("PRODUCT_ID", productId);
        Object obj = this.invoke("condition.execConditionStrategy",jsonObject);
        JSONObject CG01 = JSONObject.parseObject(JSONObject.toJSONString(obj));
        double referTax = CG01.getDoubleValue("P001");
        Map map = MapUtil.mapper("VIP_ALLIANCE", "0001",
                "BUSINESS_CIRCLE_ID",jo.getString("businessCircleId"),"CLASSIFY_ID",classifyId,
                "DKLX",jo.getIntValue("DKLX") ,"PRODUCT_ID", productId,
                "DISCOUNT_TYPE", discountType,"ITEM_TYPE", type,
                "ORDER_TYPE", "","CLASSIFY_ID_FIRST", classifyId.substring(0, 1),
                "PRICE_OUT_UNIT_IN_TAX", 0, "ORIGINAL_SALES_UNIT_PRICE", jo.getDoubleValue("originalSalesUnitPrice"),
                "REFER_TAX", referTax,"AMOUNT_USED", jo.getDoubleValue("amountUsed"));
        //取会员联盟策略
        JSONObject VIP_SETTLE = getConditionStrategy(map, "VIP_SETTLE");
        map.putAll(VIP_SETTLE);
        if ("1".equals(VIP_SETTLE.getString("sys_break")) && !"1".equals(map.get("OUT_SYSTEM_BUSINESS").toString()))
            throw new RuntimeException("未能取到会员联盟结算策略");
        //应结金额
        double settlementAmount = getVipSettleItemSettlementAmount(map);
        return MapUtil.mapper("settlementAmount",settlementAmount,"referTaxStrategy",CG01.getString("C_ID"),"vipSettleStrategy",VIP_SETTLE.getString("C_ID"));
    }
}
